/**********************************************************************/
/*                                                                    */
/*      COMP.C                                                        */
/*                                                                    */
/*      Copyright (c) 1995 - 2000  Microsoft Corporation                */
/*                                                                    */
/**********************************************************************/
#include "stdafx.h"
#include <windows.h>
#include <strsafe.h>
#include <imm.h>
#include "resource.h"
#include "imeapps.h"

LRESULT HandleStartComposition(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	COMPOSITIONFORM cpf = {0};
	HIMC hIMC = NULL;

#ifdef DEBUG
	OutputDebugString(TEXT("WM_STARTCOMPOSITIONSTRING!!!\r\n"));
#endif

	if (fdwProperty & IME_PROP_SPECIAL_UI)
	{
		// Normally, we need to set the composition window
		// position to caret position for a special UI IME
	}
	else if (fdwProperty & IME_PROP_AT_CARET)
	{
		// If an application show composition string by itself, we do not
		// need to set the position of composition window for an at caret
		// IME.

		return 1;
	}
	else
	{
		// Normally, we need to set the composition window
		// position to caret position for a near caret IME
	}

	hIMC = ImmGetContext(hWnd);

	if (!hIMC)
	{
		return 1;
	}

	cpf.dwStyle = CFS_POINT;
	cpf.ptCurrentPos.x = ptImeUIPos.x;
	cpf.ptCurrentPos.y = ptImeUIPos.y;

	ImmSetCompositionWindow(hIMC,&cpf);

	ImmReleaseContext(hWnd,hIMC);

	return 1;
}

LRESULT HandleEndComposition(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
#ifdef DEBUG
	OutputDebugString(TEXT("WM_ENDCOMPOSITIONSTRING!!!\r\n"));
#endif
	dwCompStrLen      = 0;
	dwCompAttrLen     = 0;
	dwCompClsLen      = 0;
	dwCompReadStrLen  = 0;
	dwCompReadAttrLen = 0;
	dwCompReadClsLen  = 0;
	dwResultStrLen      = 0;
	dwResultClsLen      = 0;
	dwResultReadStrLen  = 0;
	dwResultReadClsLen  = 0;
	InvalidateRect(hWnd,NULL,TRUE);

	return 1;
}

void MakePaintString(HWND hWnd, LPTSTR lpStr, DWORD dwStrLen, LPDWORD lpCls, DWORD dwClsLen, LPTSTR lpPaintStr, DWORD dwPaintStrSize)
{
	LPTSTR lpPaintStart = lpPaintStr;

	lpPaintStr += lstrlen(lpPaintStr);

	if (dwStrLen)
	{
		if (dwClsLen)
		{
			lpCls[127] = 0;

			while (*(lpCls+1) && *lpCls < dwStrLen)
			{
				DWORD dwTextLen = *(lpCls+1) - *lpCls;
				LPTSTR lpT = lpStr + *lpCls;

				memcpy(lpPaintStr,lpT,dwTextLen * sizeof(TCHAR));
				lpPaintStr += dwTextLen;
				*lpPaintStr = TEXT(',');
				lpPaintStr++;
				lpCls++;
			}
			*lpPaintStr = TEXT('\0');
		}
		else
		{
			StringCchCopy((LPTSTR)lpPaintStr,dwPaintStrSize, (LPTSTR)lpStr);
			StringCchCat((LPTSTR)lpPaintStr,dwPaintStrSize, (LPTSTR)TEXT(","));
		}
	}

}

LRESULT HandleComposition(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	HIMC hIMC = NULL;
	BOOL fRedraw = FALSE;

	hIMC = ImmGetContext(hWnd);	
	if (lParam & GCS_COMPSTR)
	{
		dwCompStrLen = ImmGetCompositionString(hIMC, GCS_COMPSTR, szCompStr, sizeof(szCompStr));
		dwCompStrLen /= sizeof(TCHAR);
		szCompStr[dwCompStrLen] = TEXT('\0');
		fRedraw = TRUE;
	}
	else
	{
		dwCompStrLen = 0;
		szCompStr[0] = TEXT('\0');
	}

	if (lParam & GCS_COMPATTR)
	{
		dwCompAttrLen = ImmGetCompositionString(hIMC, GCS_COMPATTR, bCompAttr, sizeof(bCompAttr));
		fRedraw = TRUE;
	}
	else
	{
		dwCompAttrLen = 0;
		bCompAttr[0] = 0;
	}

	if (lParam & GCS_COMPCLAUSE)
	{
		dwCompClsLen = ImmGetCompositionString(hIMC, GCS_COMPCLAUSE, dwCompCls, sizeof(dwCompCls));
		fRedraw = TRUE;
	}
	else
	{
		dwCompClsLen = 0;
		dwCompCls[0] = 0;
		dwCompCls[1] = 0;
	}


	if (lParam & GCS_COMPREADSTR)
	{
		dwCompReadStrLen = ImmGetCompositionString(hIMC, GCS_COMPREADSTR, szCompReadStr, sizeof(szCompReadStr));
		dwCompReadStrLen /= sizeof(TCHAR);
		szCompReadStr[dwCompReadStrLen] = TEXT('\0');
		fRedraw = TRUE;
	}
	else
	{
		dwCompReadStrLen = 0;
		szCompReadStr[0] = TEXT('\0');
	}

	if (lParam & GCS_COMPREADATTR)
	{
		dwCompReadAttrLen = ImmGetCompositionString(hIMC, GCS_COMPREADATTR, bCompReadAttr, sizeof(bCompReadAttr));
		fRedraw = TRUE;
	}
	else
	{
		dwCompReadAttrLen = 0;
		bCompReadAttr[0] = 0;
	}

	if (lParam & GCS_COMPREADCLAUSE)
	{
		dwCompReadClsLen = ImmGetCompositionString(hIMC, GCS_COMPREADCLAUSE, dwCompReadCls, sizeof(dwCompReadCls));
		fRedraw = TRUE;
	}
	else
	{
		dwCompReadClsLen = 0;
		dwCompReadCls[0] = 0;
		dwCompReadCls[1] = 0;
	}


	if (lParam & GCS_RESULTSTR)
	{
		RECT rc = {0};
		HDC hIC = NULL;
		SIZE sz0, sz1;
		HFONT hOldFont = NULL;

		if (lParam & GCS_RESULTCLAUSE)
		{
			dwResultClsLen = ImmGetCompositionString(hIMC, GCS_RESULTCLAUSE, dwResultCls, sizeof(dwResultCls));
		}
		else
		{
			dwResultClsLen = 0;
			dwResultCls[0] = 0;
			dwResultCls[1] = 0;
		}

		dwResultStrLen = ImmGetCompositionString(hIMC, GCS_RESULTSTR, szResultStr, sizeof(szResultStr));
		dwResultStrLen /= sizeof(TCHAR);
		szResultStr[dwResultStrLen] = TEXT('\0');


		// szPaintResult may overflow..
		GetClientRect(hWnd,&rc);
		hIC = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);
		hOldFont = (HFONT)SelectObject(hIC,hFont);

		GetTextExtentPoint(hIC, szPaintResult, lstrlen(szPaintResult), &sz0);
		GetTextExtentPoint(hIC, szResultStr, lstrlen(szResultStr), &sz1);


		if (sz0.cx + sz1.cx >= rc.right)
		{
			szPaintResult[0] = TEXT('\0');
			szPaintResultRead[0] = TEXT('\0');
		}
		SelectObject(hIC,hOldFont);
		DeleteDC(hIC);

		MakePaintString(hWnd,szResultStr,dwResultStrLen,dwResultCls,dwResultClsLen,szPaintResult, ARRAYSIZE(szPaintResult));

		fRedraw = TRUE;
	}
	else
	{
		dwResultStrLen = 0;
		szResultStr[0] = TEXT('\0');
		dwResultClsLen = 0;
		dwResultCls[0] = 0;
		dwResultCls[1] = 0;
	}



	if (lParam & GCS_RESULTREADSTR)
	{
		if (lParam & GCS_RESULTREADCLAUSE)
		{
			dwResultReadClsLen = ImmGetCompositionString(hIMC,GCS_RESULTREADCLAUSE,dwResultReadCls,sizeof(dwResultReadCls));
			fRedraw = TRUE;
		}
		else
		{
			dwResultReadClsLen = 0;
			dwResultReadCls[0] = 0;
			dwResultReadCls[1] = 0;
		}
		dwResultReadStrLen = ImmGetCompositionString(hIMC,GCS_RESULTREADSTR,szResultReadStr,sizeof(szResultReadStr));
		dwResultReadStrLen /= sizeof(TCHAR);
		szResultReadStr[dwResultReadStrLen] = TEXT('\0');
		MakePaintString(hWnd,szResultReadStr,dwResultReadStrLen,dwResultReadCls,dwResultReadClsLen,szPaintResultRead, ARRAYSIZE(szPaintResultRead));
		fRedraw = TRUE;
	}
	else
	{
		dwResultReadStrLen = 0;
		szResultReadStr[0] = TEXT('\0');
		dwResultReadClsLen = 0;
		dwResultReadCls[0] = 0;
		dwResultReadCls[1] = 0;
	}

	if (lParam & GCS_CURSORPOS)
	{		
		DWORD dwPos = ImmGetCompositionString(hIMC, GCS_CURSORPOS, NULL, 0);
		fRedraw = TRUE;		
		StringCchPrintf(szCursor, _countof(szCursor), L"%d", dwPos);
	}
	else
	{
		szCursor[0] = 0;
	}
	if (lParam & GCS_DELTASTART)
	{		
		DWORD dwDelta = ImmGetCompositionString(hIMC, GCS_DELTASTART, NULL, 0);
		fRedraw = TRUE;		
		StringCchPrintf(szDelta, _countof(szDelta), L"%d", dwDelta);
	}
	else
	{
		szDelta[0] = 0;
	}

	if (fRedraw)
	{
		InvalidateRect(hWnd,NULL,TRUE);
		UpdateWindow(hWnd);
	}
	return 1;
}


LRESULT HandleChar(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	RECT rc = {0};
	HDC hIC = NULL;
	SIZE sz0, sz1;
	HFONT hOldFont = NULL;
	LPTSTR lp = NULL;
	// is the previous received char is a DBCS lead byte char ?
	static BOOL fIsPrevLeadByte = FALSE;

	GetClientRect(hWnd,&rc);
	hIC = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);
	hOldFont = (HFONT)SelectObject(hIC,hFont);

	GetTextExtentPoint(hIC,szPaintResult,lstrlen(szPaintResult),&sz0);
	GetTextExtentPoint(hIC,szResultStr,lstrlen(szResultStr),&sz1);

	if (sz0.cx + sz1.cx >= rc.right)
	{
		szPaintResult[0] = TEXT('\0');
		szPaintResultRead[0] = TEXT('\0');
	}
	SelectObject(hIC,hOldFont);
	DeleteDC(hIC);

	lp = szPaintResult + lstrlen(szPaintResult);

#ifndef USEWAPI
	if (fIsPrevLeadByte) 
	{
		// remove , and append second byte for showing DBCS char
		if (*(lp - 1) == ',') 
		{
			lp--;
		}
	}
#endif

	// append second byte
	*lp++ = (TCHAR)(BYTE)wParam;
	*lp++ = TEXT(',');
	*lp++ = TEXT('\0');

	lp = szPaintResultRead + lstrlen(szPaintResultRead);

#ifndef USEWAPI
	if (fIsPrevLeadByte) 
	{
		// remove , and append second byte for showing DBCS char
		if (*(lp - 1) == ',') 
		{
			lp--;
		}

		fIsPrevLeadByte = FALSE;
	} 
	else 
	{
		fIsPrevLeadByte = IsDBCSLeadByte((BYTE)wParam);
	}
#endif

	*lp++ = (BYTE)wParam;
	*lp++ = TEXT(',');
	*lp++ = TEXT('\0');

	InvalidateRect(hWnd,NULL,TRUE);
	UpdateWindow(hWnd);

	return 1;
}


LRESULT HandleNotify(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HIMC hIMC = NULL;
	BOOL fOpen = FALSE;
	DWORD dwConvMode, dwSentMode;

	
	switch (wParam)
	{
	case IMN_OPENSTATUSWINDOW: /* fall-through */
	case IMN_CLOSESTATUSWINDOW:
		break;

	case IMN_SETOPENSTATUS:
		SetStatusItems(hWnd);

		hIMC = ImmGetContext(hWnd);
		fOpen = ImmGetOpenStatus(hIMC);
		UpdateShowOpenStatusButton(fOpen);

		ImmReleaseContext(hWnd,hIMC);
		break;

	case IMN_SETCONVERSIONMODE:
		hIMC = ImmGetContext(hWnd);
		fOpen = ImmGetOpenStatus(hIMC);
		ImmGetConversionStatus(hIMC,&dwConvMode,&dwSentMode);
		if (fOpen)
		{
			SetConvModeParts(dwConvMode);
			UpdateModeButton(dwConvMode);
		}
		else
		{
			ClearConvModeParts();
		}
		ImmReleaseContext(hWnd,hIMC);
		break;

	case IMN_OPENCANDIDATE:
		if (!fShowCand || (lParam != 0x01))
		{
			if (fdwProperty & IME_PROP_SPECIAL_UI)
			{
				// Normally, we only need to set the composition window
				// position for a special UI IME
			}
			else if (fdwProperty & IME_PROP_AT_CARET)
			{
				CANDIDATEFORM cdf;
				HIMC          hIMC;

				hIMC = ImmGetContext(hWnd);

				cdf.dwIndex = 0;
				cdf.dwStyle = CFS_CANDIDATEPOS;
				cdf.ptCurrentPos.x = ptImeUIPos.x;
				cdf.ptCurrentPos.y = ptImeUIPos.y;
				ImmSetCandidateWindow(hIMC,&cdf);

				ImmReleaseContext(hWnd,hIMC);
			}
			else
			{
				// Normally, we only need to set the composition window
				// position for a near caret IME
			}

			return (DefWindowProc(hWnd, message, wParam, lParam));
		}

	case IMN_CHANGECANDIDATE:

#ifdef _DEBUG
		{
			TCHAR szDev[80];
			DWORD dwSize;
			LPCANDIDATELIST lpC;

			hIMC = ImmGetContext(hWnd);
			if (dwSize = ImmGetCandidateList(hIMC,0x0,NULL,0))
			{
				lpC = (LPCANDIDATELIST)GlobalAlloc(GPTR,dwSize);

				ImmGetCandidateList(hIMC,0x0,lpC,dwSize);

				OutputDebugString(TEXT("DumpCandList!!!\r\n"));
				StringCchPrintf((LPTSTR)szDev,ARRAYSIZE(szDev),TEXT("dwCount %d\r\n"),lpC->dwCount);
				OutputDebugString((LPTSTR)szDev);
				StringCchPrintf((LPTSTR)szDev,ARRAYSIZE(szDev),TEXT("dwSelection %d\r\n"),lpC->dwSelection);
				OutputDebugString((LPTSTR)szDev);
				StringCchPrintf((LPTSTR)szDev,ARRAYSIZE(szDev),TEXT("dwPageStart %d\r\n"),lpC->dwPageStart);
				OutputDebugString((LPTSTR)szDev);
				StringCchPrintf((LPTSTR)szDev,ARRAYSIZE(szDev),TEXT("dwPageSize %d\r\n"),lpC->dwPageSize);
				OutputDebugString((LPTSTR)szDev);
				GlobalFree((HANDLE)lpC);
			}
		}
#endif
		if (fShowCand && (lParam == 0x01))
		{
			DWORD dwSize;

			if (!lpCandList)
				lpCandList = (LPCANDIDATELIST)GlobalAlloc(GPTR,sizeof(CANDIDATELIST));

			hIMC = ImmGetContext(hWnd);
			if (dwSize = ImmGetCandidateList(hIMC,0x0,NULL,0))
			{
				GlobalFree((HANDLE)lpCandList);
				lpCandList = (LPCANDIDATELIST)GlobalAlloc(GPTR,dwSize);

				ImmGetCandidateList(hIMC,0x0,lpCandList,dwSize);
			}
			else
			{
				memset(lpCandList, 0, sizeof(CANDIDATELIST));
			}

			InvalidateRect(hWndCandList,NULL,TRUE);
			UpdateWindow(hWndCandList);


			ImmReleaseContext(hWnd,hIMC);
		}
		else
		{
			return (DefWindowProc(hWnd, message, wParam, lParam));
		}
		break;

	case IMN_CLOSECANDIDATE:
		if (fShowCand && (lParam == 0x01))
		{
			if (!lpCandList)
			{
				lpCandList = (LPCANDIDATELIST)GlobalAlloc(GPTR,sizeof(CANDIDATELIST));
			}

			memset(lpCandList, 0, sizeof(CANDIDATELIST));
			InvalidateRect(hWndCandList,NULL,TRUE);
			UpdateWindow(hWndCandList);
		}
		else
		{
			return (DefWindowProc(hWnd, message, wParam, lParam));
		}
		break;

	case IMN_GUIDELINE:
		{
			DWORD dwLevel = ImmGetGuideLine(hIMC, GGL_LEVEL, NULL, 0);
			INPUTCONTEXT* pInput = NULL;
			pInput = (INPUTCONTEXT*)ImmLockIMC(hIMC);
			if (pInput)
			{
				GUIDELINE* pGuidLine = (GUIDELINE*)ImmLockIMCC(pInput->hGuideLine);
				if (pGuidLine)
				{
					StringCchPrintf(szGuideLine, _countof(szGuideLine), L"%08X-%08X-%08X-%08X-%08X-%08X-%08X\n", pGuidLine->dwSize, pGuidLine->dwLevel, pGuidLine->dwIndex, pGuidLine->dwStrLen, pGuidLine->dwStrOffset, pGuidLine->dwPrivateSize, pGuidLine->dwPrivateOffset);					
				}
			}
			return (DefWindowProc(hWnd, message, wParam, lParam));
		}
		break;
	default:
		return (DefWindowProc(hWnd, message, wParam, lParam));
	}

	return 0;
}
